package com.dpfmanage.api.project.dpfmanage.util;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import java.io.*;

import java.net.HttpURLConnection;

import java.net.URL;

import java.net.URLEncoder;

import java.security.InvalidKeyException;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.text.SimpleDateFormat;

import java.util.*;


public class ECloudSignature {

    public static final String VERSION = "Version";
    public static final String ACCESS_KEY = "AccessKey";
    public static final String TIME_STAMP = "Timestamp";
    public static final String SIGNATURE = "Signature";
    public static final String SIGNATURE_METHOD = "SignatureMethod";
    public static final String SIGNATURE_VERSION = "SignatureVersion";
    public static final String SIGNATURE_NONCE = "SignatureNonce";
    public static final String SIGNATURE_VERSION_VALUE = "V2.0";
    public static final String SIGNATURE_METHOD_VALUE = "HmacSHA1";
    public static final String TIME_STAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    public static final String URL_ENCODER_FORMAT = "%s=%s";
    public static final String ENCODING = "utf-8";
    public static final String STRING_SEPARATOR = "\n";
    public static final String PARAMETER_SEPARATOR = "&";
    public static final String SIGNING_STRING = "BC_SIGNATURE&";
    public String accessKey;
    public String secretKey;
    private SimpleDateFormat sdf = new SimpleDateFormat(TIME_STAMP_FORMAT);


    //参数排序及整理

    public static String percentEncode(String value) throws

            UnsupportedEncodingException {

        return value != null ? URLEncoder.encode(value, ENCODING).replace("+",

                "%20").replace("*", "%2A").replace("%7E", "~") : null;

    }


    //参数编码

    public static String sign(String secretKey, String data) {

        try {

            Mac mac = Mac.getInstance(SIGNATURE_METHOD_VALUE);

            byte[] secretKeyByte = secretKey.getBytes(ENCODING);

            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyByte,

                    SIGNATURE_METHOD_VALUE);

            mac.init(secretKeySpec);

            return new String(encodeHex(mac.doFinal(data.getBytes(ENCODING))));

        } catch (NoSuchAlgorithmException | InvalidKeyException |

                 UnsupportedEncodingException e) {

            return null;

        }

    }


    //计算签名

    public static String encode(String data) throws

            UnsupportedEncodingException, NoSuchAlgorithmException {

        MessageDigest digest = MessageDigest.getInstance("SHA-256");

        byte[] hash = digest.digest(data.getBytes(ENCODING));

        return new String(encodeHex(hash));

    }

    protected static char[] encodeHex(final byte[] data) {

        char[] toDigits =

                {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',

                        'c', 'd', 'e', 'f'};

        final int l = data.length;

        final char[] out = new char[l << 1];

        // two characters form the hex value.

        for (int i = 0, j = 0; i < l; i++) {

            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];

            out[j++] = toDigits[0x0F & data[i]];

        }

        return out;

    }

    public static String doForResponse(String httpurl, String httpMethod) {
        HttpURLConnection connection = null;
        InputStream is = null;
        BufferedReader br = null;
        String result = null;
        try {

            URL url = new URL(httpurl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod(httpMethod);
            connection.setConnectTimeout(15000);
            connection.setReadTimeout(60000);
            connection.connect();
            System.out.println(connection.getContent().toString());
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                StringBuffer sbf = new StringBuffer();
                Scanner scanner = new Scanner(br);
                while (scanner.hasNextLine()) {
                    sbf.append(scanner.nextLine());
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (null != br) {
                try {
                    br.close();
                    is.close();
                } catch (IOException e) {

                    System.out.println(e);
                }
            }
            connection.disconnect();

        }
        return result;
    }

    public static void main(String[] args) {

        ECloudSignature e = new ECloudSignature();
        //您的accessKey
        e.accessKey = "61266a1b6ac5407dae07f484c23b8fe8";
        //您的secretKey
        e.secretKey = "c0f38a7557534913a90722acc8116fc1";
        String uri = e.doSignature("/api/v2/region", "GET", new HashMap<>());
        String hp = String.format("https://api-chongqing-1.cmecloud.cn:8443");
        String result = doForResponse(hp + uri, "POST");

        System.out.println(result);

    }

    public String doSignature(String servletPath, String method, Map<String, Object> query) {
        try {
            servletPath = java.net.URLDecoder.decode(servletPath, ENCODING);
            query.put(ACCESS_KEY, accessKey);
            query.put(TIME_STAMP, sdf.format(new Date()));
            query.put(SIGNATURE_NONCE, UUID.randomUUID().toString().replace("-",
                    ""));
            query.put(SIGNATURE_VERSION, SIGNATURE_VERSION_VALUE);
            query.put(SIGNATURE_METHOD, SIGNATURE_METHOD_VALUE);
//            query.put(VERSION,"2016-12-05");
            ArrayList<String> parameterList = new ArrayList<>(query.keySet());
            Collections.sort(parameterList);
            List<String> list = new ArrayList<>(query.size());
            for (String name : parameterList) {
                if (!SIGNATURE.equalsIgnoreCase(name)) {
                    String value;
                    if (query.get(name) instanceof Boolean) {
                        value = Boolean.getBoolean(name) ? "true" : "false";
                    } else {
                        value = query.get(name).toString();
                    }
                    list.add(String.format(URL_ENCODER_FORMAT,
                            percentEncode(name), percentEncode(value)));
                }
            }
            String canonicalizedQueryString = String.join(PARAMETER_SEPARATOR, list);
            String encryptedCanonicalizedQueryStr = encode(canonicalizedQueryString);
            StringBuilder sb = new StringBuilder();
            sb.append(method.toUpperCase());
            sb.append(STRING_SEPARATOR);
            sb.append(percentEncode(servletPath));
            sb.append(STRING_SEPARATOR);
            sb.append(encryptedCanonicalizedQueryStr);
            String signature = sign(SIGNING_STRING + secretKey, sb.toString());
            if (Objects.isNull(signature) || signature.length() == 0) {
                return null;
            }
            return servletPath + "?" + canonicalizedQueryString + PARAMETER_SEPARATOR + String.format(URL_ENCODER_FORMAT, SIGNATURE, percentEncode(signature));
        } catch (Exception e) {
            return null;
        }
    }
}